package com.guli.gulimall.product.web.controller;

import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName HiController
 * @Author Hao_YunKai
 * @Date 2022/1/6 18:16
 */
@RestController
public class DemoController {

    @Autowired
    private RedissonClient client;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @GetMapping("/hello")
    public String hello() {
        //获取锁
        RLock myLock = client.getLock("myLock");
        //加锁 默认过期时间 30s
        myLock.lock();
        try {
            // 执行业务
            System.out.println(Thread.currentThread().getId() + "执行业务");
            Thread.sleep(50000);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 释放锁
            System.out.println(Thread.currentThread().getId() + "释放锁...");
            myLock.unlock();
        }
        return "error";
    }

    // 写锁
    @GetMapping("write")
    public String write() {
        // 获取读写锁
        RReadWriteLock wrlock = client.getReadWriteLock("wrlock");
        // 获取写锁
        RLock rLock = wrlock.writeLock();
        // 加锁
        rLock.lock();
        String uuid = "";
        try {
            System.out.println(Thread.currentThread().getId() + "写锁执行任务...");
            uuid = UUID.randomUUID().toString().replace("-", "");
            redisTemplate.opsForValue().set("writeValue", uuid, 5, TimeUnit.MINUTES);
            // 业务等待50s
            Thread.sleep(50000);
            return uuid;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放写锁
            System.out.println(Thread.currentThread().getId() + "释放写锁...");
            rLock.unlock();
        }
        return uuid;
    }

    /**
     * 读锁 + 读锁 = 无锁
     * 读锁 + 写锁 先读在写 阻塞
     * 写锁 + 读锁
     * 写锁 + 写锁 阻塞等待
     */
    // 读锁
    @GetMapping("read")
    public String read() {
        // 获取读写锁
        RReadWriteLock wrlock = client.getReadWriteLock("wrlock");
        // 获取读锁
        RLock rLock = wrlock.readLock();
        // 加锁
        rLock.lock();
        String uuid = "";
        try {
            // 执行业务
            System.out.println(Thread.currentThread().getId() + "读锁执行任务...");
            uuid = redisTemplate.opsForValue().get("writeValue");
            // 业务等待50s
            Thread.sleep(50000);
            return uuid;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放写锁
            System.out.println(Thread.currentThread().getId() + "释放读锁...");
            rLock.unlock();
        }
        return uuid;
    }

    //停车
    @GetMapping("/park")
    public String park() {
        //获取信号量
        RSemaphore park = client.getSemaphore("park");
        try {
            //尝试获取信号量
            boolean b = park.tryAcquire();
            if (b) {
                System.out.println(Thread.currentThread().getId() + "停车成功");
                return "ok";
            } else {
                System.out.println(Thread.currentThread().getId() + "停车失败");
                return "error";
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return "error";
    }

    // 离开
    @GetMapping("/go")
    public String go() {
        //获取信号量
        RSemaphore park = client.getSemaphore("park");
        try {
            park.release();
            System.out.println(Thread.currentThread().getId() + "离开...");
            return "ok";
        } catch (Exception e) {
            e.printStackTrace();
            return "error";
        }
    }

    //分布式闭锁
    @GetMapping("lockDoor")
    public String lockDoor() throws InterruptedException {
        RCountDownLatch door = client.getCountDownLatch("door");
        door.trySetCount(5);
        door.await();//阻塞等待
        return "放假了";
    }

    //放假班级走
    @GetMapping("/classGo/{id}")
    public String classGo(@PathVariable("id")String id) {
        RCountDownLatch door = client.getCountDownLatch("door");
        door.countDown();// 计数
        System.out.println(id + "班级走了" + Thread.currentThread().getId());
        return id + "班级走了";
    }
}
